package com.joyplus.report.business.service;

import com.alibaba.fastjson.JSON;
import com.joyplus.report.business.dao.MdCampaignsDao;
import com.joyplus.report.business.document.DistributionPvUvStatisticsDocument;
import com.joyplus.report.business.document.DistributionPvUvStatisticsFreDocument;
import com.joyplus.report.business.document.DistributionPvUvStatisticsFreFullDocument;
import com.joyplus.report.business.document.DistributionPvUvStatisticsFullDocument;
import com.joyplus.report.business.document.DistributionPvUvStatisticsHourDocument;
import com.joyplus.report.business.document.DistributionPvUvStatisticsLocationDocument;
import com.joyplus.report.business.document.DistributionPvUvStatisticsLocationFullDocument;
import com.joyplus.report.business.domain.StatisticsFre;
import com.joyplus.report.business.domain.MdCampaigns;
import com.joyplus.report.business.domain.PvUvModel;
import com.mongodb.AggregationOutput;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.Fields;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.joyplus.report.common.service.BaseService;
import javax.annotation.Resource;


/**
 * Service
 *
 * @author jeff
 * @date 2018-05-29
 */
@Service
@Transactional
public class MdCampaignsService extends BaseService<MdCampaignsDao, MdCampaigns> {

  @Resource
  private MdCampaignsDao mdCampaignsDao;

  @Autowired
  //@Qualifier(value = "primaryMongoTemplate")
      MongoTemplate mongoTemplate;


  public List<DistributionPvUvStatisticsDocument> AggregationById(Integer id) {
    List<DistributionPvUvStatisticsDocument> document = new ArrayList<>();
    BasicDBObject append1 = new BasicDBObject("date", "$date")
        .append("campaign_id", "$campaign_id");
    BasicDBObject append = new BasicDBObject("date", "$_id.date")
        .append("campaign_id", "$_id.campaign_id").append("uv", "$uv").append("pv", "$pv");
    BasicDBObject cond = new BasicDBObject("campaign_id", id + "");
    DBObject match = new BasicDBObject("$match", cond);
    DBObject groupFields1 = new BasicDBObject("_id", append1);
    groupFields1.put("pv", new BasicDBObject("$sum", "$pv"));
    groupFields1.put("uv", new BasicDBObject("$sum", "$uv"));
    DBObject group1 = new BasicDBObject("$group", groupFields1);
    DBObject project = new BasicDBObject("$project", append);
    List<DBObject> pipeline = new ArrayList();
    pipeline.add(match);
    pipeline.add(group1);
    pipeline.add(project);
    AggregationOutput pvUvStatistics = mongoTemplate
        .getCollection("distribute_machine_statistics").aggregate(pipeline);
    Iterable<DBObject> results = pvUvStatistics.results();
    for (DBObject dbObject : results) {
      String s = JSON.toJSONString(dbObject);
      DistributionPvUvStatisticsDocument distributionPvUvStatisticsDocument = JSON
          .parseObject(s, DistributionPvUvStatisticsDocument.class);
      int l = Integer.parseInt(distributionPvUvStatisticsDocument.getCampaignId());
      MdCampaigns mdCampaigns1 = new MdCampaigns();
      mdCampaigns1.setCampaignId(l);
      MdCampaigns mdCampaigns = this.getById(l);
      distributionPvUvStatisticsDocument.setCampaignName(mdCampaigns.getCampaignName());
      document.add(distributionPvUvStatisticsDocument);
    }
    return document;
  }


  public List getPlanDistribution(String[] id, String stratDate, String endDate) {
    List<DBObject> pipeline = new ArrayList();
    BasicDBObject groupAppend = new BasicDBObject("campaign_id", "$campaign_id")
        .append("date", "$date");
    BasicDBObject projectAppend = new BasicDBObject("campaign_id", "$_id.campaign_id")
        .append("date", "$_id.date")
        .append("pv", "$pv").append("uv", "$uv").append("_id", 0);
    BasicDBObject sortAppend = new BasicDBObject("date", 1);

    BasicDBObject cond = new BasicDBObject("date",
        new BasicDBObject("$lte", endDate).append("$gte", stratDate));
    BasicDBObject cond1 = new BasicDBObject("campaign_id", new BasicDBObject("$in", id));
    BasicDBList dbList = new BasicDBList();
    dbList.add(cond);
    dbList.add(cond1);
    DBObject match = new BasicDBObject("$match", new BasicDBObject("$and", dbList));
    DBObject groupFields = new BasicDBObject("_id", groupAppend);
    groupFields.put("pv", new BasicDBObject("$sum", "$pv"));
    groupFields.put("uv", new BasicDBObject("$sum", "$uv"));
    DBObject group = new BasicDBObject("$group", groupFields);
    DBObject project = new BasicDBObject("$project", projectAppend);
    DBObject sort = new BasicDBObject("$sort", sortAppend);
    pipeline.add(match);
    pipeline.add(group);
    pipeline.add(project);
    pipeline.add(sort);
    AggregationOutput pvUvStatistics = mongoTemplate
        .getCollection("distribution_pv_uv_statistics").aggregate(pipeline);
    Iterable<DBObject> results = pvUvStatistics.results();
    List<DBObject> collect = StreamSupport.stream(results.spliterator(), false)
        .collect(Collectors.toList());

    HashMap<String, DistributionPvUvStatisticsDocument> map = new HashMap<>();

    List<DistributionPvUvStatisticsDocument> distributionPvUvStatisticsDocuments = JSON
        .parseArray(JSON.toJSONString(collect), DistributionPvUvStatisticsDocument.class);
    PvUvModel pvUvModel = new PvUvModel();
    List<PvUvModel> list = new ArrayList<>();
    for (DistributionPvUvStatisticsDocument doc : distributionPvUvStatisticsDocuments
        ) {
      pvUvModel = new PvUvModel();
      if (map.get(doc.getCampaignId()) == null) {
        list = new ArrayList<>();
        MdCampaigns byId = mdCampaignsDao.getById(Long.parseLong(doc.getCampaignId()));
        doc.setCampaignName(byId.getCampaignName());
        pvUvModel.setTaskDate(doc.getDate());
        pvUvModel.setPv(doc.getPv());
        pvUvModel.setUv(doc.getUv());
        list.add(pvUvModel);
        doc.setList(list);
        map.put(doc.getCampaignId(), doc);
      } else {
        DistributionPvUvStatisticsDocument document = map
            .get(doc.getCampaignId());
        pvUvModel.setTaskDate(doc.getDate());
        pvUvModel.setPv(doc.getPv());
        pvUvModel.setUv(doc.getUv());
        document.getList().add(pvUvModel);
        map.put(doc.getCampaignId(), document);
      }
    }
    distributionPvUvStatisticsDocuments = new ArrayList<>();

    Iterator<Entry<String, DistributionPvUvStatisticsDocument>> iterator = map.entrySet()
        .iterator();

    while (iterator.hasNext()) {
      distributionPvUvStatisticsDocuments.add(iterator.next().getValue());
    }

    return distributionPvUvStatisticsDocuments;
  }

  /**
   * 获取小时
   */
  public List getPlanDistributionByHour(String[] id, String stratDate, String endDate) {
    Criteria criteria = new Criteria().andOperator(Criteria.where("campaign_id").in(id),
        Criteria.where("date").gte(stratDate), Criteria.where("date").lte(endDate));
    Aggregation customerAgg1 = Aggregation.newAggregation(
        Aggregation.match(criteria),
        Aggregation.group(Fields.fields("hour", "date", "campaign_id")).sum("pv").as("pv").sum("uv")
            .as("uv"),
        Aggregation.project(Fields.fields("hour", "date", "campaign_id", "pv", "uv")),
        Aggregation.sort(new Sort(new Order(Direction.ASC, "hour")))
    );
    AggregationResults<DistributionPvUvStatisticsHourDocument> document = mongoTemplate
        .aggregate(customerAgg1, "distribution_pv_uv_statistics_hour",
            DistributionPvUvStatisticsHourDocument.class);
    List<DistributionPvUvStatisticsHourDocument> mappedResults = document.getMappedResults();
    HashMap<String, DistributionPvUvStatisticsHourDocument> map = new HashMap<>();
    PvUvModel model = new PvUvModel();
    List<PvUvModel> pvUvModels = new ArrayList<>();
    for (DistributionPvUvStatisticsHourDocument doc : document) {
      model = new PvUvModel();
      pvUvModels = new ArrayList<>();
      if (map.get(doc.getCampaignId() + doc.getDate()) == null) {
        model.setPv(doc.getPv());
        model.setUv(doc.getUv());
        model.setTaskDate(doc.getDate());
        model.setTaskHour(doc.getHour());
        pvUvModels.add(model);
        doc.setList(pvUvModels);
        MdCampaigns byId = mdCampaignsDao.getById(Long.parseLong(doc.getCampaignId()));
        doc.setCampaignName(byId.getCampaignName());
        map.put(doc.getCampaignId() + doc.getDate(), doc);
      } else {
        DistributionPvUvStatisticsHourDocument hourDocument = map
            .get(doc.getCampaignId() + doc.getDate());
        model.setPv(doc.getPv());
        model.setUv(doc.getUv());
        model.setTaskDate(doc.getDate());
        model.setTaskHour(doc.getHour());
        hourDocument.getList().add(model);
        map.put(doc.getCampaignId() + doc.getDate(), hourDocument);
      }
    }

    Iterator<Entry<String, DistributionPvUvStatisticsHourDocument>> iterator = map.entrySet()
        .iterator();
    mappedResults = new ArrayList<>();

    while (iterator.hasNext()) {
      mappedResults.add(iterator.next().getValue());
    }

    return mappedResults;
  }


  /**
   * 获取频次
   */
  public List getPlanDistributionByFre(String[] id, String stratDate, String endDate, int pageNum,
      int pageSize) {
    Query query = new Query();
    if (id.length == 0) {
      Criteria criteria = new Criteria().andOperator(
          Criteria.where("date").gte(stratDate), Criteria.where("date").lte(endDate));
      query.addCriteria(criteria);
    } else {
      Criteria criteria = new Criteria().andOperator(
          Criteria.where("campaign_id").in(id),
          Criteria.where("date").gte(stratDate), Criteria.where("date").lte(endDate));
      query.addCriteria(criteria);
    }

    query.with(new Sort(Direction.ASC, "fre"));
    List<DistributionPvUvStatisticsFreDocument> documents = mongoTemplate
        .find(query, DistributionPvUvStatisticsFreDocument.class);
    List<StatisticsFre> list = new ArrayList<>();
    StatisticsFre statisticsFre = new StatisticsFre();
    HashMap<String, StatisticsFre> map = new HashMap<>();
    for (DistributionPvUvStatisticsFreDocument doc : documents
        ) {
      try {
        if (map.get(doc.getCampaignId()) != null) {
          statisticsFre = map.get(doc.getCampaignId());
          statisticsFre.setCampaignId(doc.getCampaignId());
          statisticsFre.setTaskDate(doc.getDate());
          if (doc.getFre() >= 12) {
            int pv = ((int) (doc.getCount())) * ((int) (doc.getFre()));
            int totalpv = statisticsFre.getPv12() + pv;
            int count = (int) doc.getCount() + statisticsFre.getN12();
            statisticsFre.setN12(count);
            statisticsFre.setPv12(totalpv);
          } else {
            Method method = statisticsFre.getClass()
                .getDeclaredMethod("setN" + (int) doc.getFre(), Integer.class);
            method.invoke(statisticsFre, (int) doc.getCount());

            method = statisticsFre.getClass()
                .getDeclaredMethod("setPv" + (int) doc.getFre(), Integer.class);
            method.invoke(statisticsFre, ((int) doc.getCount() * (int) doc.getFre()));
          }
        } else {
          statisticsFre = new StatisticsFre();
          statisticsFre.setCampaignId(doc.getCampaignId());
          if (doc.getFre() >= 12) {
            int count = (int) doc.getCount() + statisticsFre.getN12();
            statisticsFre.setN12(count);
          } else {
            Method method = statisticsFre.getClass()
                .getDeclaredMethod("setN" + (int) doc.getFre(), Integer.class);
            method.invoke(statisticsFre, (int) doc.getCount());

            method = statisticsFre.getClass()
                .getDeclaredMethod("setPv" + (int) doc.getFre(), Integer.class);
            method.invoke(statisticsFre, (int) doc.getCount() * (int) doc.getFre());
          }
        }
        map.put(doc.getCampaignId(), statisticsFre);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

    Iterator<Entry<String, StatisticsFre>> iterator = map.entrySet()
        .iterator();
    while (iterator.hasNext()) {
      statisticsFre = iterator.next().getValue();
      MdCampaigns byId = mdCampaignsDao
          .getById(Long.parseLong(statisticsFre.getCampaignId()));

      statisticsFre.setCampaignName(byId.getCampaignName());
      list.add(statisticsFre);
    }

    return list;
  }


  /**
   * 获取geo
   */
  public List<DistributionPvUvStatisticsLocationDocument> getPlanDistributionByLocation(String[] id,
      String stratDate, String endDate) {
    Query query = new Query();
    Criteria criteria = new Criteria().andOperator(Criteria.where("campaign_id").in(id),
        Criteria.where("date").gte(stratDate), Criteria.where("date").lte(endDate));
    Aggregation customerAgg1 = Aggregation.newAggregation(
        Aggregation.match(criteria),
        Aggregation.group(Fields.fields("province", "campaign_id")).sum("pv").as("pv").sum("uv")
            .as("uv"),
        Aggregation.project(Fields.fields("province", "pv", "uv"))
    );
    System.out.println(customerAgg1.toString());
    AggregationResults<DistributionPvUvStatisticsLocationDocument> document = mongoTemplate
        .aggregate(customerAgg1, "distribution_pv_uv_statistics_location",
            DistributionPvUvStatisticsLocationDocument.class);

    List<DistributionPvUvStatisticsLocationDocument> mappedResults = document.getMappedResults();
    HashMap<String, DistributionPvUvStatisticsLocationDocument> map = new HashMap<>();
    DistributionPvUvStatisticsLocationDocument bena = new DistributionPvUvStatisticsLocationDocument();
    List<DistributionPvUvStatisticsLocationDocument> list = new ArrayList<>();
    for (DistributionPvUvStatisticsLocationDocument doc : mappedResults
        ) {
      if (map.get(doc.getCampaignId()) == null) {
        list = new ArrayList<>();
        bena = new DistributionPvUvStatisticsLocationDocument();
        bena.setCampaignId(doc.getCampaignId());
        MdCampaigns byId = mdCampaignsDao.getById(Long.parseLong(doc.getCampaignId()));
        bena.setCampaignName(byId.getCampaignName());
        bena.setTotalAmount(byId.getTotalAmount());
        bena.setTotalPv(doc.getPv());
        bena.setTotalUv(doc.getUv());
        list.add(doc);
        bena.setList(list);
        map.put(doc.getCampaignId(), bena);
      } else {
        bena = map.get(doc.getCampaignId());
        bena.setTotalPv(doc.getPv() + bena.getTotalPv());
        bena.setTotalUv(doc.getUv() + bena.getTotalUv());
        bena.getList().add(doc);
        map.put(doc.getCampaignId(), bena);
      }
    }

    Iterator<Entry<String, DistributionPvUvStatisticsLocationDocument>> iterator = map.entrySet()
        .iterator();
    list = new ArrayList<>();
    while (iterator.hasNext()) {
      list.add(iterator.next().getValue());
    }

    return list;
  }

  /**
   * 获取geo
   */
  public List getPlanDistributionCityByLocation(String[] id, String stratDate, String endDate,
      String province) {

    Criteria criteria = new Criteria().andOperator(Criteria.where("campaign_id").in(id),
        Criteria.where("date").gte(stratDate), Criteria.where("date").lte(endDate),
        Criteria.where("province").is(province));
    Aggregation customerAgg1 = Aggregation.newAggregation(
        Aggregation.match(criteria),
        Aggregation.group(Fields.fields("province", "city", "campaign_id")).sum("pv").as("pv")
            .sum("uv")
            .as("uv"),
        Aggregation.project(Fields.fields("province", "city", "pv", "uv"))
    );
    System.out.println(customerAgg1.toString());
    AggregationResults<DistributionPvUvStatisticsLocationDocument> document = mongoTemplate
        .aggregate(customerAgg1, "distribution_pv_uv_statistics_location",
            DistributionPvUvStatisticsLocationDocument.class);
    List<DistributionPvUvStatisticsLocationDocument> mappedResults = document.getMappedResults();
    return mappedResults;
  }


  public List getFreqFull(String id) {
    Query query = new Query();
    Criteria criteria = Criteria.where("campaign_id").in(id);
    query.addCriteria(criteria);
    List<DistributionPvUvStatisticsFreFullDocument> fullDocuments = mongoTemplate
        .find(query, DistributionPvUvStatisticsFreFullDocument.class);
    return fullDocuments;
  }

  /**
   * 获取全程实际的uv/pv
   */
  public List getDistributionFull(String[] id) {
    Query query = new Query();
    Criteria criteria = Criteria.where("campaign_id").in(id);
    query.addCriteria(criteria);
    List<DistributionPvUvStatisticsFullDocument> fullDocuments = mongoTemplate
        .find(query, DistributionPvUvStatisticsFullDocument.class);

    for (DistributionPvUvStatisticsFullDocument doc: fullDocuments
    ) {
      doc.setCampaignName(mdCampaignsDao.getById(Long.parseLong(doc.getCampaignId())).getCampaignName());
    }

    return fullDocuments;
  }


  /**
   * 获取实际地域的uv/pv
   */
  public List<DistributionPvUvStatisticsLocationFullDocument> getDistributionLocationFull(
      String[] id) {
    Query query = new Query();
    Criteria criteria = Criteria.where("campaign_id").in(id);
    query.addCriteria(criteria);

    Aggregation aggregation = Aggregation.newAggregation(
        Aggregation.match(criteria),
        Aggregation.group("province", "campaign_id").sum("pv").as("pv").sum("uv").as("uv"),
        Aggregation.project("province", "campaign_id", "pv", "uv")
    );

    AggregationResults<DistributionPvUvStatisticsLocationFullDocument> aggregate = mongoTemplate
        .aggregate(aggregation, "distribution_pv_uv_statistics_location_full",
            DistributionPvUvStatisticsLocationFullDocument.class);

    List<DistributionPvUvStatisticsLocationFullDocument> fullDocuments = aggregate
        .getMappedResults();
    HashMap<String, DistributionPvUvStatisticsLocationFullDocument> map = new HashMap<>();

    DistributionPvUvStatisticsLocationFullDocument bena = null;
    List<DistributionPvUvStatisticsLocationFullDocument> list = null;
    for (DistributionPvUvStatisticsLocationFullDocument doc : fullDocuments
        ) {
      if (map.get(doc.getCampaignId()) == null) {
        list = new ArrayList<>();
        bena = new DistributionPvUvStatisticsLocationFullDocument();
        bena.setCampaignId(doc.getCampaignId());
        MdCampaigns byId = mdCampaignsDao.getById(Long.parseLong(doc.getCampaignId()));
        bena.setCampaignName(byId.getCampaignName());
        bena.setTotalAmount(byId.getTotalAmount());
        bena.setTotalPv(doc.getPv());
        bena.setTotalUv(doc.getUv());
        list.add(doc);
        bena.setList(list);
        map.put(doc.getCampaignId(), bena);
      } else {
        bena = map.get(doc.getCampaignId());
        bena.setTotalPv(doc.getPv() + bena.getTotalPv());
        bena.setTotalUv(doc.getUv() + bena.getTotalUv());
        bena.getList().add(doc);
        map.put(doc.getCampaignId(), bena);
      }
    }

    Iterator<Entry<String, DistributionPvUvStatisticsLocationFullDocument>> iterator = map
        .entrySet()
        .iterator();
    list = new ArrayList<>();
    while (iterator.hasNext()) {
      list.add(iterator.next().getValue());
    }

    return list;
  }

  /**
   * 获取实际地域市级的uv/pv
   */
  public List getDistributionCityFeull(String id, String province) {
    Query query = new Query();
    Criteria criteria = new Criteria()
        .andOperator(Criteria.where("campaign_id").in(id), Criteria.where("province").is(province));
    query.addCriteria(criteria);
    List<DistributionPvUvStatisticsLocationFullDocument> fullDocuments = mongoTemplate
        .find(query, DistributionPvUvStatisticsLocationFullDocument.class);
    return fullDocuments;
  }
}
